<?php

require_once "ApiServicesInterface.php";
require_once __DIR__ . "/../lib/FPString.php";
require_once __DIR__ . "/../lib/Constant.php";
require_once __DIR__ . "/../lib/LogUtil.php";
require_once __DIR__ . "/../lib/RequestUtil.php";
require_once __DIR__ . "/../lib/Signature.php";


/**
 * Class AbstractService
 * time 2020/11/11 12:01
 * author zrone <xujining415@gmail.com>
 * copyright zrone <xujining415@gmail.com>
 */
class AbstractService implements ApiServicesInterface
{
    // 签名未验证时重试，不知道接口什么鬼，没有仔细研究，频繁提示签名不通过。引入一个重试机制做兼容
    public $retry = 3;

    // 延迟重试等待时间，限制频率, 微秒级
    public $delay = 500000;

    public $clock = 0;

    public function getCommonParams(string $action): array
    {
        // TODO: Implement getCommonParams() method.
        date_default_timezone_set("UTC");
        $data = [
            "Action" => $action,
            "Version" => "2015-11-23",
            "Format" => "JSON",
            "AccessKeyId" => Constant::ACCESSKEY_ID,
            "SignatureMethod" => "HMAC-SHA1",
            "SignatureNonce" => FPString::uuid(false),
            "SignatureVersion" => "1.0",
            "Timestamp" => date("Y-m-d\TH:i:s\Z", time()),
            "RegionId" => "cn-hangzhou"
        ];
        return $data;
    }

    public function request(array $logicParams, string $action, string $method = 'GET'): string
    {
        $method = strtoupper($method);

        if (!in_array($method, ['GET', 'POST'])) {
            LogUtil::log(1, "未定义的请求方法 " . date("Y/m/d H:i:s"));
            exit("未定义的请求方法");
        }

        $data = $this->getCommonParams($action);

        $signature = new Signature;
        // TODO: Implement request() method.
        if ($method == 'GET') {
            $data["Signature"] = $signature(array_merge($data, $logicParams), "GET");
            $queryString = urldecode(http_build_query($data)) . "&" . http_build_query($logicParams);

            return RequestUtil::request(
                Constant::DOMAIN . "?" . $queryString
            );
        } else {

            $data["Signature"] = $signature(array_merge($data, $logicParams), "POST");

            return RequestUtil::request(
                Constant::DOMAIN,
                'POST',
                null,
                array_merge($data, $logicParams)
            );
        }
    }

    public function terminal(array $logicParams, string $action, string $method = 'GET'): array
    {
        // TODO: Implement terminal() method.

        $content = $this->request($logicParams, $action, $method);
        $result = json_decode($content, true);

        if (isset($result['Code']) && $result['Code'] == 'SignatureDoesNotMatch') {
            LogUtil::log(1, "操作{$action}签名不匹配重试第" . ($this->getClock()+1) . "次 " . date("Y/m/d H:i:s"));
            // 开始重试
            if($this->getClock() < $this->retry) {
                $this->incrementClock();
                usleep($this->delay);
                return $this->terminal($logicParams, $action, $method);
            }
        }

        return $result;
    }

    /**
     * @return int
     */
    public function getClock(): int
    {
        return $this->clock;
    }

    public function incrementClock(): void
    {
        $this->clock++;
    }
}